package connection

import (
	"encoding/base64"
	"encoding/json"
	"game_server/framework/global"
	"game_server/framework/message"
	"game_server/framework/router"
	"game_server/framework/task"
	"github.com/duke-git/lancet/v2/cryptor"
	"github.com/duke-git/lancet/v2/strutil"
	"github.com/gorilla/websocket"
	"github.com/spf13/viper"
	"sync"
)

const (
	CONNECTING = 1
	EXITING    = 2
)

type ConnectionWrapper struct {
	RWLock     sync.RWMutex
	UserId     int64
	Conn       *websocket.Conn
	readerChan chan *message.MessageWrapper
	handleChan chan *task.TaskWrapper
	senderChan chan *message.MessageWrapper
	status     int
}

func (c *ConnectionWrapper) ConnectionWrapperInitialize() {
	c.readerChan = make(chan *message.MessageWrapper, 10)
	c.handleChan = make(chan *task.TaskWrapper, 10)
	c.senderChan = make(chan *message.MessageWrapper, 10)
	c.status = CONNECTING
	go c.reader()
	go c.handle()
	go c.sender()
}

func (c *ConnectionWrapper) reader() {
	mode := viper.GetString("environment.mode")
	encryptKey := viper.GetString("environment.encrypt-key")
	for {
		_, p, err := c.Conn.ReadMessage()
		if err != nil {
			_connectionManager.RemoveConn(c.UserId)
			return
		}
		if mode == "pro" {
			encodedStr, err := base64.StdEncoding.DecodeString(strutil.BytesToString(p))
			if err != nil {
				continue
			}
			//global.Logger.Infof("encodeToString:%v", encodedStr)
			p = cryptor.DesEcbDecrypt(encodedStr, []byte(encryptKey))
		}
		messageWrapper := &message.MessageWrapper{}
		err = json.Unmarshal(p, messageWrapper)
		if err != nil {
			continue
		}
		taskWrapper := &task.TaskWrapper{
			ReceiverId:     c.UserId,
			MessageWrapper: messageWrapper,
		}
		c.handleChan <- taskWrapper
		//global.Logger.Info("readerChan<-message:", convertor.ToString(messageWrapper))
	}
}

func (c *ConnectionWrapper) handle() {
	for {
		select {
		case taskWrapper, ok := <-c.handleChan:
			if !ok {
				return
			}
			//global.Logger.Info("handleChan->taskWrapper:", convertor.ToString(taskWrapper))
			handler := router.RouterManagerInstance().QueryRouter(taskWrapper.MessageWrapper.Code)
			if handler == nil {
				continue
			}
			taskWrapper = handler(taskWrapper)
			if taskWrapper == nil {
				continue
			}
			connectionWrappers := _connectionManager.QueryConnMultiple(taskWrapper.SenderIds)
			for _, item := range connectionWrappers {
				item.Receive(taskWrapper.MessageWrapper)
			}
		}
	}
}

func (c *ConnectionWrapper) sender() {
	mode := viper.GetString("environment.mode")
	encryptKey := viper.GetString("environment.encrypt-key")
	for {
		select {
		case messageWrapper, ok := <-c.senderChan:
			if !ok {
				return
			}
			//global.Logger.Info("senderChan->messageWrapper:", convertor.ToString(messageWrapper))
			bytes, err := json.Marshal(messageWrapper)
			if err != nil {
				continue
			}
			if mode == "pro" {
				bytes = cryptor.DesEcbEncrypt(bytes, []byte(encryptKey))
				err = c.Conn.WriteMessage(websocket.TextMessage, []byte(base64.StdEncoding.EncodeToString(bytes)))
			} else {
				err = c.Conn.WriteMessage(websocket.TextMessage, bytes)
			}
			if err != nil {
				continue
			}
		}
	}
}

func (c *ConnectionWrapper) Receive(messageWrapper *message.MessageWrapper) {
	defer c.RWLock.RUnlock()
	c.RWLock.RLock()
	if c.status == EXITING {
		return
	}
	c.senderChan <- messageWrapper
}

func (c *ConnectionWrapper) release() {
	defer func() {
		err := recover()
		if err != nil {
			global.Logger.Errorf("err:%v", err)
		}
	}()
	defer global.Logger.Info("package:[connection]:::function:[release]<======")
	defer c.RWLock.Unlock()
	c.RWLock.Lock()
	global.Logger.Infof("======>package:[connection]:::function:[release]:::id:%v", c.UserId)
	c.status = EXITING
	close(c.readerChan)
	close(c.handleChan)
	close(c.senderChan)
	c.Conn.Close()
}
